var scroller;
var gl;
var verticesBuffer;
var vertexIndexBuffer;
var vertexTextureCoordBuffer;
var shaderProgram;
var canvases = [];
var contentItems = [];
var scrollers = [];
var text = ["\u4E00\u4E01\u4E02\u4E03\u4E04\u4E05\u4E06\u4E07\u4E08\u4E09\u4E0a\u4E0b\u4E0c\u4E0d\u4E0e\u4E0f"];
var imageCount = 0;
var mouseDown = false;
var lastMouseX = 0;
var canvasIndex = 0;
var currentCanvasPosition = 0;
var interactivityTimeout = 5000;
var interactivityTimerID;
var isStopped = false;
var prefs = new gadgets.Prefs();   

rd.scroller.main = {};

// Called when the canvas is created to get the ball rolling.
function start() {
    initWebGL();
    initShaders();
    
    if (!shaderProgram) {
	return;
    }
    
    initBuffers();
    initContent();
    
    //gl.clearColor(255.0, 255.0, 255.0, 0.0);	//Transparent white background
    gl.enable(gl.DEPTH_TEST);
    
    tick();
}

// Initialize WebGL, returning the GL context or null if
// WebGL isn't available or could not be initialized.
// Remember: you can only initialize one context per element.
function initWebGL() {
    scroller = document.getElementById('scroller');
    scroller.width = prefs.getString("rsW");
    scroller.height = prefs.getString("rsH");

    var names = ["webgl", "experimental-webgl", "webkit-3d", "moz-webgl"];
    
    for (var ii = 0; ii < names.length; ++ii) {
	try {
	    gl = scroller.getContext(names[ii]);
	}
	catch(e) {}
	
	if (gl) {
	    gl.viewportWidth = scroller.width;
	    gl.viewportHeight = scroller.height;
	    
	    return;
	}
    }
    
    alert('Oops, something went wrong...');
}

function initShaders() {
    var fragmentShader = getShader(gl, "shader-fs");
    var vertexShader = getShader(gl, "shader-vs");

    shaderProgram = gl.createProgram();
    gl.attachShader(shaderProgram, vertexShader);
    gl.attachShader(shaderProgram, fragmentShader);
    gl.linkProgram(shaderProgram);

    if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
	alert("Could not initialise shaders");
    }

    gl.useProgram(shaderProgram);

    shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
    gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);

    shaderProgram.textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord");
    gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute);

    shaderProgram.pMatrixUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");
    shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");
    shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler");
}

function getShader(gl, id) {
    var shaderScript = document.getElementById(id);
    if (!shaderScript) {
	return null;
    }

    var str = "";
    var k = shaderScript.firstChild;
    while (k) {
	if (k.nodeType == 3) {
	    str += k.textContent;
	}
	k = k.nextSibling;
    }

    var shader;
    if (shaderScript.type == "x-shader/x-fragment") {
	shader = gl.createShader(gl.FRAGMENT_SHADER);
    } else if (shaderScript.type == "x-shader/x-vertex") {
	shader = gl.createShader(gl.VERTEX_SHADER);
    } else {
	return null;
    }

    gl.shaderSource(shader, str);
    gl.compileShader(shader);

    if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
	alert(gl.getShaderInfoLog(shader));
	return null;
    }

    return shader;
}

//This is what gets rendered.
//Buffers are the objects that hold our geometry data.
function initBuffers() {
    //Text
    verticesBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, verticesBuffer);

    //2D rectangle	
    var vertices = [-1, -1, 1, -1, 1, 1, -1, 1];
			
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
    verticesBuffer.itemSize = 2;
    verticesBuffer.numItems = 4;
    
    vertexTextureCoordBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, vertexTextureCoordBuffer);
    var textureCoords = [
	0.0, 0.0,	//bottom left
	1.0, 0.0,
	1.0, 1.0,	//top right
	0.0, 1.0
    ];
    
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoords), gl.STATIC_DRAW);
    vertexTextureCoordBuffer.itemSize = 2;
    vertexTextureCoordBuffer.numItems = 4;

    vertexIndexBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, vertexIndexBuffer);
    var vertexIndices = [
	    0, 1, 2,      0, 2, 3    // Front face
    ];
    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(vertexIndices), gl.STATIC_DRAW);
    vertexIndexBuffer.itemSize = 1;
    vertexIndexBuffer.numItems = 6;
    
    //Image
    cubeVertexPositionBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer);
    vertices = [
	// Front face
	-0.5, -1,  0.0,
	 0.5, -1,  0.0,
	 0.5,  1,  0.0,
	-0.5,  1,  0.0
    ];
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
    cubeVertexPositionBuffer.itemSize = 3;
    cubeVertexPositionBuffer.numItems = 4;

    cubeVertexTextureCoordBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexTextureCoordBuffer);
    var textureCoords = [
      // Front face
      0.0, 0.0,
      1.0, 0.0,
      1.0, 1.0,
      0.0, 1.0
    ];
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoords), gl.STATIC_DRAW);
    cubeVertexTextureCoordBuffer.itemSize = 2;
    cubeVertexTextureCoordBuffer.numItems = 4;

    // This array defines each face as two triangles, using the
    // indices into the vertex array to specify each triangle's
    // position.
    cubeVertexIndexBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer);
    var cubeVertexIndices = [
	0, 1, 2,      0, 2, 3    // Front face
    ];
    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(cubeVertexIndices), gl.STATIC_DRAW);
    cubeVertexIndexBuffer.itemSize = 1;
    cubeVertexIndexBuffer.numItems = 6;
}

//Create separate canvas for each text and image.	
function initContent() {
    //Create two Scroller objects.
    for (var i = 0; i < 3; i++) {
	scrollers[i] = new Scroller(scroller.width, scroller.height, 2 * i + 2);
    }
    
    //Do this for every sports team (game?) or financial instrument.
    for (var i = 0; i < logos.length; i++) {
	contentItems[i] = new ContentItem(text[i], logos[i]);
	contentItems[i].loadImage(onImageLoaded);	
    }
}

function onImageLoaded() {
    imageCount++;
	
    //All images have been loaded.
    if (imageCount == logos.length) {
	for (var i = 0; i < contentItems.length; i++) {
	    canvases[i] = contentItems[i].createCanvas(i);
	}
	
	//Initialize textures for each scroller.
	for (var i = 0; i < scrollers.length; i++) {
	    scrollers[i].prepareCanvas();
	    scrollers[i].createTextureFromCanvas();	    	    		
	}
    }
}

//This should draw something slightly different each time.
function drawScene() {
    gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    
    for (var i = 0; i < scrollers.length; i++) {
	scrollers[i].draw(mouseDown, isStopped);	    	    		
    } 
}

function handleMouseDown(event) {
    mouseDown = true;
    lastMouseX = event.clientX;
}

function handleMouseUp(event) {
    mouseDown = false;
    isStopped = true;
    
    interactivityTimerID = setTimeout(function() {
	isStopped = false;
    }, interactivityTimeout);
}

function handleMouseMove(event) {
    if (!mouseDown) {
	return;
    }
    
    var newX = event.clientX;
    var deltaX = newX - lastMouseX;
    var units = 2 * deltaX / scroller.width;	//2 units across * deltaX / width of placeholder
    
    for (var i = 0; i < scrollers.length; i++) {
	scrollers[i].setPosition(units);
    }
    
    lastMouseX = newX;
}

function isPowerOfTwo(value) {
    return ((value & (value - 1)) == 0);
}

function tick() {
    requestAnimFrame(tick);
    
    for (var i = 0; i < scrollers.length; i++) {
	scrollers[i].animate(mouseDown, isStopped);
    }
    
    drawScene();
}

// Matrix utility functions
var mvMatrix = mat4.create();
var mvMatrixStack = [];
var pMatrix = mat4.create();
	
function mvPushMatrix() {
    var copy = mat4.create();
    mat4.set(mvMatrix, copy);
    mvMatrixStack.push(copy);
}

function mvPopMatrix() {
    if (mvMatrixStack.length == 0) {
	throw "Invalid popMatrix!";
    }
    mvMatrix = mvMatrixStack.pop();
}

function setMatrixUniforms() {
    gl.uniformMatrix4fv(shaderProgram.pMatrixUniform, false, pMatrix);
    gl.uniformMatrix4fv(shaderProgram.mvMatrixUniform, false, mvMatrix);
}

function degToRad(degrees) {
    return degrees * Math.PI / 180;
}

function initialize() {
    var id = prefs.getString("id");
    var backgroundColor = prefs.getString("backgroundColor");
		
    if (backgroundColor !== null && backgroundColor != "") {
	document.body.style.background = backgroundColor;
    }
    
    if (id !== null && id != "") {
	gadgets.rpc.register("rscmd_play_" + id, play);
	gadgets.rpc.register("rscmd_pause_" + id, pause);
    }
    
    var mvMatrix = mat4.create();
    var mvMatrixStack = [];
    var pMatrix = mat4.create();

    readyEvent();
}	    

function play() {
    start();
    //window.venue.startContentTimer();
}

function pause() {
    //window.venue.stopContentTimer();
}

function stop() {
    //window.venue.stopContentTimer();
}

// sends "READY" event to the Viewer
function readyEvent() {
    gadgets.rpc.call('', 'rsevent_ready', null, prefs.getString("id"), true, true, true, true, true);
}

// sends "DONE" event to the Viewer
function doneEvent() {
    gadgets.rpc.call('', 'rsevent_done', null, prefs.getString("id"));
}

gadgets.util.registerOnLoadHandler(initialize);